﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace TodoSoft.Controls
{
	/// <summary>
	/// Древовидное представление табличных данных, с группировкой по одному или нескольким столбцам.
	/// </summary>
	public partial class TreeGrid : ScrollPanel
	{
		public TreeGrid()
		{
			InitializeComponent();
		}

		public event Action<TreeGridCell> CellClick;
		private bool _locationsCalculated;

		public readonly List<TreeGridGroup> Groups = new List<TreeGridGroup>();
		public readonly List<TreeGridRow> TopLevelRows = new List<TreeGridRow>();
		public readonly List<TreeGridRow> SelectedRows = new List<TreeGridRow>();

		public IEnumerable<TreeGridRow> AllVisibleRows
		{
			get { return GetVisibleRows(TopLevelRows); }
		}

		private IEnumerable<TreeGridRow> GetVisibleRows(IEnumerable<TreeGridRow> topLevelRows)
		{
			foreach (var row in topLevelRows.Where(row => row.Expanded))
			{
				yield return row;

				foreach (var childRow in GetVisibleRows(row.Children))
				{
					yield return childRow;
				}
			}
		}

		public virtual void UpdateView()
		{
			int currentY = 0;
			int width = 0;

			//Headers height;
			foreach (var level in Groups)
			{
				int currentX = 0;
				foreach (var column in level.Columns)
				{
					column.Left = currentX;
					currentX += column.Width;
				}
				width = Math.Max(width, currentX);

				if (level.HeaderRow.Visible)
				{
					level.HeaderRow.Top = currentY;
					currentY += level.HeaderRow.Height;
				}
			}

			foreach (var row in AllVisibleRows)
			{
				row.Top = currentY;
				currentY += row.Height;
			}
			
			SetScrollArea(width, currentY);
			_locationsCalculated = true;

			Invalidate();
		}

		void PaintRows(Graphics graphics, Rectangle clipRectangle)
		{
			foreach (var row in AllVisibleRows)
			{
				if(row.Bottom >= clipRectangle.Top)
					row.Paint(graphics);

				if (row.Top > clipRectangle.Bottom)
					break;
			}
		}

		private void PaintHeaders(Graphics graphics, Rectangle clipRectangle)
		{
			foreach (var level in Groups.Where(level => level.HeaderRow.Visible))
			{
				level.HeaderRow.Paint(graphics);
			}
		}

		public void Clear()
		{
			TopLevelRows.Clear();
		}

		protected override void PaintContent(Graphics graphics, Rectangle clipRectangle)
		{
            base.PaintContent(graphics, clipRectangle);

			if (!_locationsCalculated)
				return;
			PaintHeaders(graphics, clipRectangle);
			PaintRows(graphics, clipRectangle);
		}

		internal TreeGridGroup AddLevel()
		{
			var level = new TreeGridGroup();
			level.HeaderRow.Width = Width;
			Groups.Add(level);
			return level;
		}

		TreeGridCell FindCell(int x, int y)
		{
			return (from row in AllVisibleRows 
			        where y > row.Top && y < row.Bottom 
			        from column in row.Group.Columns
			        where x > column.Left && x < column.Right 
			        select new TreeGridCell {Column = column, Row = row}).FirstOrDefault();
		}

		protected override void OnMouseDown(MouseEventArgs e)
		{
			var visibleArea = VisibleArea;
			var cell = FindCell(e.X + visibleArea.X, e.Y + visibleArea.Y);
			if (cell == null) return;
			if (CellClick != null)
				CellClick(cell);
			cell.Click();
		}

		public void SetGroupings(List<TreeGridGroup> groups)
		{
			Groups.Clear();

			foreach (var treeGridGroup in groups)
			{
				treeGridGroup.HeaderRow.Width = Width;
				Groups.Add(treeGridGroup);
			}
		}
	}
}

